/*
 * 础石OS	-- 设备树
 *
 * Copyright (C) 2022 国科础石(重庆)软件有限公司
 *
 * 作者: Hengxing Wu<wuhengxing@kernelsoft.com>
 * 	 Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <linux/compiler.h>
#include <dim-sum/devtree.h>
#include <dim-sum/errno.h>
#include <dim-sum/printk.h>
#include <dim-sum/string.h>
#include <dim-sum/init.h>
#include <dim-sum/smp_rwlock.h>
#include <dim-sum/irqflags.h>
#include <dim-sum/preempt.h>
#include <dim-sum/beehive.h>
#include <asm/sections.h>
#include <asm/div64.h>
#include <asm/devtree.h>
#include <dim-sum/device.h>

/**
 * 单板设备树句柄
 */
struct devtree_handle {
	/**
	 * 设备树根节点
	 */
	struct device_node *root;
	struct dt_nidtbl *nidtbl;
	u32 nidtbl_count;
};

static struct devtree_handle dt_handle;

/*
 *判断设备树节点type属性是否相同
 */
static bool _node_is_type(const struct device_node *node, const char *type)
{
	const char *match = dt_get_property(node, "device_type");

	return node && match && type && !strcmp(match, type);

}

int dt_addr_cells(const struct device_node *node)
{
	u32 cells;

	if (node->parent)
		node = node->parent;

	for (; node; node = node->parent) {
		if (!dt_read_u32(node, "#address-cells", &cells))
			return cells;
	}

	return DT_ROOT_NODE_ADDR_CELLS_DEFAULT;
}

int dt_size_cells(const struct device_node *node)
{
	u32 cells;

	if (node->parent)
		node = node->parent;

	for (; node; node = node->parent) {
		if (!dt_read_u32(node, "#size-cells", &cells))
			return cells;
	}

	return DT_ROOT_NODE_SIZE_CELLS_DEFAULT;
}

static struct property *_find_property(const struct device_node *node, const char *name)
{
	struct property *prop;

	for_each_property_of_node(prop, node) {
		if (strcmp(prop->name, name) == 0)
			return prop;
	}

	return NULL;
}

/*
 *获取给定node的成员属性
 */
struct property *dt_find_property(const struct device_node *node, const char *name)
{
	struct device_node *nd = (struct device_node *)node;
	struct property *prop;
	unsigned long flags;

	if (!node || !name)
		return NULL;

	smp_read_lock_irqsave(&nd->prop.lock, flags);
	prop = _find_property(nd, name);
	smp_read_unlock_irqrestore(&nd->prop.lock, flags);

	return prop;
}


/*
 *获取给定node的成员属性值
 */
const void *dt_get_property(const struct device_node *node, const char *name)
{
	struct property *prop;

	if (!node || !name)
		return NULL;

	prop = dt_find_property(node, name);

	return prop ? prop->value : NULL;
}

/*
 *获取给定node的成员属性值长度
 */
u32 dt_property_size(const struct device_node *node, const char *name)
{
	struct property *prop;

	if (!node || !name)
		return 0;

	prop = dt_find_property(node, name);

	return prop ? prop->len : 0;
}

const void *dt_get_property_and_size(const struct device_node *node, const char *name, u32 *out)
{
	struct property *prop;

	if (!node || !name)
		return NULL;

	prop = dt_find_property(node, name);
	if (!prop)
		return NULL;

	if (out)
		*out = prop->len;
	
	return prop->value;
}

/*
 *判断给定node是否存在属性
 */
bool dt_have_property(const struct device_node *node)
{
	struct device_node *np = (struct device_node *)node;
	unsigned long flags;
	bool ret;

	if (!np)
		return FALSE;

	smp_read_lock_irqsave(&np->prop.lock, flags);
	ret = list_is_empty(&np->prop.list) ? FALSE : TRUE;
	smp_read_unlock_irqrestore(&np->prop.lock, flags);

	return ret;
}

/*
 *设置给定node节点属性值
 */
int dt_set_property(struct device_node *node, const char *name, void *value, u32 len)
{
	unsigned long flags;
	struct property *pp;

	if (!node || !name || (len && !value))
		return -EINVAL;

	/*
	 *删除原有的属性值
	 */
	dt_delete_property(node, name);

	/*
	 *设置新的属性值
	 */
	pp = kmalloc(sizeof(struct property), PAF_ATOMIC);
	if (!pp)
		return -ENOMEM;
	list_init(&pp->list);
	pp->len = len;
	pp->value = NULL;
	strncpy(pp->name, name, sizeof(pp->name));
	if (pp->len) {
		pp->value = kmalloc(pp->len, PAF_ATOMIC);
		if (!pp->value) {
			kfree(pp);
			return -ENOMEM;
		}
		memcpy(pp->value, value, pp->len);
	}
	smp_write_lock_irqsave(&node->prop.lock, flags);
	list_insert_behind(&pp->list, &node->prop.list);
	smp_write_unlock_irqrestore(&node->prop.lock, flags);

	return 0;
}

/*
 *删除给定node的name属性
 */
int dt_delete_property(struct device_node *node, const char *name)
{
	unsigned long flags;
	struct property *pp;

	if (!node || !name)
		return -EINVAL;

	pp = dt_find_property(node, name);
	if (!pp)
		return -EINVAL;

	kfree(pp->value);

	smp_write_lock_irqsave(&node->prop.lock, flags);
	list_del(&pp->list);
	smp_write_unlock_irqrestore(&node->prop.lock, flags);

	kfree(pp);

	return 0;
}

static int _getpath(char **out, size_t *out_len, const struct device_node *node)
{
	size_t len;
	int ret;

	if (!node)
		return -EINVAL;

	if (node->parent) {
		ret = _getpath(out, out_len, node->parent);
		if (ret)
			return ret;
		if (*out_len < 2)
			return -ENOSPC;
		**out = DT_PATH_SEPARATOR;
		(*out) += 1;
		**out = '\0';
		*out_len -= 1;
	}

	len = strlen(node->name);

	if (*out_len < (len + 1))
		return -ENOSPC;

	strncpy(*out, node->name, len);
	(*out) += len;
	**out = '\0';
	*out_len -= len;

	return 0;
}

/*
 *获取node的路径信息
 */
int dt_node_get_path(char *out, size_t out_len, const struct device_node *node)
{
	size_t out_ptr_len = out_len;
	char *out_ptr = out;
	int ret;

	if (!node || !out || (out_len < 2))
		return -EINVAL;

	out[0] = 0;

	/*
	 *迭代获取整个节点路径信息
	 */
	ret = _getpath(&out_ptr, &out_ptr_len, node);
	if (ret)
		return ret;

	if (strcmp(out, "") == 0) {
		out[0] = DT_PATH_SEPARATOR;
		out[1] = '\0';
	}

	return 0;
}

struct device_node *dt_get_parent(const struct device_node *node)
{
	struct device_node *np = NULL;

	if (!node)
		return NULL;
	if (node->parent)
		np = dt_node_hold(node->parent);
	return np;
}

static struct device_node
	*dt_get_child_by_path_core(struct device_node *dt_node, const char *dt_path)
{
	struct device_node *node = dt_node, *tmp, *child;
	int isok;
	u32 len;

	while (*dt_path) {
		isok = FALSE;

		/*
		 *遍历所有子节点，并与目标path比较
		 *如果目标path为多层级子节点格式，依次遍历
		 */
		for_each_child_of_node(child, node) {
			len = strlen(child->name);
			if (strncmp(child->name, dt_path, len) == 0) {
				isok = TRUE;
				dt_path += len;
				if (*dt_path) {
					/*
					 * 匹配不成功
					 */
					if (*dt_path != DT_PATH_SEPARATOR
					    && *(dt_path + 1) != '\0') {
						dt_path -= len;
						continue;
					}

					/*
					 * 匹配成功，含有子节点路径信息
					 */
					if (*dt_path == DT_PATH_SEPARATOR)
						dt_path++;
				}
				break;
			}
		}
		if (!isok) {
			for (tmp = node; tmp && (tmp != dt_node); tmp = tmp->parent)
				dt_node_loosen(tmp);
			return NULL;
		}
		node = child;
	};
	return node;
}

/*
 *根据子节点路径得到子节点信息
 */
struct device_node *dt_get_child_by_path(struct device_node *node, const char *path)
{
	struct device_node *nodep, *tmp;

	if (!node || !path)
		return NULL;

	for (; *path == DT_PATH_SEPARATOR; path++)
;

	nodep = dt_get_child_by_path_core(node, path);
	if (!nodep)
		return NULL;

	dt_node_hold(nodep);

	for (tmp = nodep; tmp && (tmp != node); tmp = tmp->parent)
		dt_node_loosen(tmp);

	return nodep;
}

/*
 * 根据路径信息得到设备树节点
 */
struct device_node *dt_find_node_by_path(const char *path)
{
	struct device_node *tmp_root = dt_handle.root;

	if (tmp_root == NULL)
		return tmp_root;

	if (path == NULL) {
		dt_node_hold(tmp_root);
		return tmp_root;
	}

	if (strncmp(tmp_root->name, path, strlen(tmp_root->name)) != 0)
		return NULL;

	path += strlen(tmp_root->name);

	if (*path == '\0')
		return dt_get_child_by_path(tmp_root, path);

	if (*path == DT_PATH_SEPARATOR)
		path++;
	else if (*(path + 1) != '\0')
		return NULL;

	return dt_get_child_by_path(tmp_root, path);
}

/*
 *判断给定的compat与node是否匹配
 */
static int _is_device_compatible(const struct device_node *node,
				     const char *compat,
				     const char *type,
				     const char *name)
{
	int index = 0, score = 0;
	struct property *pp;
	const char *cp;

	/*
	 * 匹配优先级
	 * compatible > type > name
	 */
	if (compat && compat[0]) {
		pp = _find_property(node, "compatible");
		for (cp = dt_next_string(pp, NULL); cp;
		    cp = dt_next_string(pp, cp), index++) {
			if (strcasecmp(cp, compat) == 0) {
				score = INT_MAX/2 - (index << 2);
				break;
			}
		}

		if (!score) {
			return 0;
		}
			
	}

	if (type && type[0]) {
		if (!_node_is_type(node, type))
			return 0;
		score += 2;
	}

	if (name && name[0]) {
		if (strcmp(node->name, name))
			return 0;
		score++;
	}

	return score;
}

static const struct dt_device_id *__dt_match_node(const struct dt_device_id *matches,
					   const struct device_node *node)
{
	const struct dt_device_id *best_match = NULL;
	int score, best_score = 0;

	if (!matches)
		return NULL;

	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
		score = _is_device_compatible(node, matches->compatible,
					       matches->type, matches->name);
		
		if (score > best_score) {
			best_match = matches;
			best_score = score;
		}
		matches++;
	}

	return best_match;
}

/*
 * 判断设备树节点与驱动匹配列表是否匹配
 * 如果匹配成功，返回匹配的of_device_id项，否则返回NULL
 */
const struct dt_device_id *dt_match_node(const struct dt_device_id *matches,
					 const struct device_node *node)
{
	struct device_node *nd = (struct device_node *)node;
	const struct dt_device_id *match;
	unsigned long flags;

	if (!matches || !node)
		return NULL;

	smp_read_lock_irqsave(&nd->prop.lock, flags);
	match = __dt_match_node(matches, nd);
	smp_read_unlock_irqrestore(&nd->prop.lock, flags);

	return match;
}

/*
 * 根据of_device_id列表，找到匹配的节点或子节点
 */
struct device_node *dt_find_matching_node(struct device_node *node,
					  const struct dt_device_id *matches)
{
	struct device_node *child, *nd = NULL;

	if (!matches)
		return NULL;

	if (!node)
		node = dt_handle.root;

	/*
	 *先匹配node自己
	 */
	if (__dt_match_node(matches, node)) {
		dt_node_hold(node);
		return node;
	}

	/*
	 *再匹配子节点
	 */
	for_each_child_of_node(child, node) {
		nd = dt_find_matching_node(child, matches);
		if (nd) {
			dt_node_loosen(child);
			break;
		}
	}

	return nd;
}

/*
 *递归迭代匹配节点，如果匹配成功，回调found函数
 */
void dt_iterate_matching_node(struct device_node *node,
			      const struct dt_device_id *matches,
			      node_found_cb found,
			      void *found_data)
{
	const struct dt_device_id *mid;
	struct device_node *child;

	if (!found || !matches)
		return;

	if (!node)
		node = dt_handle.root;

	dt_node_hold(node);

	mid = dt_match_node(matches, node);
	if (mid)
		found(node, mid, found_data);

	for_each_child_of_node(child, node)
		dt_iterate_matching_node(child, matches, found, found_data);

	dt_node_loosen(node);
}


/*
 * 判断设备树节点的compatible是否匹配
 */
int is_device_compatible(const struct device_node *node, const char *compatible)
{
	struct device_node *nd = (struct device_node *)node;
	unsigned long flags;
	int res;

	if (!node)
		return 0;

	smp_read_lock_irqsave(&nd->prop.lock, flags);
	res = _is_device_compatible(nd, compatible, NULL, NULL);
	smp_read_unlock_irqrestore(&nd->prop.lock, flags);

	return res;
}

static struct device_node *_find_node_by_phandle(struct device_node *node, u32 phandle)
{
	struct device_node *child, *nd;
	u32 value;
	int ret;

	if (!node)
		return NULL;

	ret = dt_read_u32(node, "phandle", &value);
	if ((ret == 0) && (value == phandle)) {
		nd = node;
		goto found;
	}

	nd = NULL;
	for_each_child_of_node(child, node) {
		nd = _find_node_by_phandle(child, phandle);
		if (nd) {
			dt_node_loosen(child);
			break;
		}
	}

found:
	if (nd)
		dt_node_hold(nd);

	return nd;
}

/*
 * 根据dtb中的phandle找到节点
 */
struct device_node *dt_find_by_phandle(u32 phandle)
{
	if (!dt_handle.root)
		return NULL;

	return _find_node_by_phandle(dt_handle.root, phandle);
}


static int _parse_phandle_with_args(const struct device_node *np,
				    const char *list_name,
				    const char *cells_name,
				    int index,
				    struct dt_phandle_args *out)
{
	int ret = 0, size, cur_index = 0;
	struct device_node *node = NULL;
	const u32 *list, *list_end;
	u32 count, phandle;

	list = dt_get_property(np, list_name);
	if (!list)
		return -ENOENT;

	size = dt_property_size(np, list_name);
	list_end = list + size / sizeof(*list);

	while (list < list_end) {
		ret = -EINVAL;
		count = 0;

		phandle = be32_to_cpu(*list);
		list++;
		if (phandle) {
			node = dt_find_by_phandle(phandle);
			if (!node) {
				pr_err("%s: phandle not found\n", np->name);
				goto err;
			}
			if (cells_name !=NULL &&  dt_read_u32(node, cells_name, &count)) {

				printk("%s: could not get %s for %s\n",
					np->name, cells_name, node->name);
				goto err;
			}
			if (list + count > list_end) {
				pr_err("%s: args longer than attribute\n", np->name);
				goto err;
			}
		}
		ret = -ENOENT;
		if (cur_index == index) {
			if (!phandle)
				goto err;
			if (out) {
				int i;

				if (WARN_ON(count > MAX_PHANDLE_ARGS))
					count = MAX_PHANDLE_ARGS;

				out->node = node;
				out->args_count = count;
				for (i = 0; i < count; i++) {
					out->args[i] = be32_to_cpu(*list);
					list++;
				}
			} else {
				dt_node_loosen(node);
			}
			return 0;
		}

		dt_node_loosen(node);
		node = NULL;
		list += count;
		cur_index++;
	}

	ret = index < 0 ? cur_index : -ENOENT;

 err:
	if (node)
		dt_node_loosen(node);

	return ret;
}

struct device_node *dt_parse_phandle(const struct device_node *node,
				     const char *phandle_name,
				     int index)
{
	struct dt_phandle_args args;

	if (index < 0)
		return NULL;

	if (_parse_phandle_with_args(node, phandle_name, NULL, index, &args))
		return NULL;

	return args.node;
}

int dt_parse_phandle_with_args(const struct device_node *node,
			       const char *list_name,
			       const char *cells_name,
			       int index,
			       struct dt_phandle_args *out)
{
	if (index < 0)
		return -EINVAL;

	return _parse_phandle_with_args(node, list_name, cells_name, index, out);
}

int dt_phandle_count_with_args(const struct device_node *node,
			       const char *list_name,
			       const char *cells_name)
{
	return _parse_phandle_with_args(node, list_name, cells_name, -1, NULL);
}

struct device_node *dt_node_hold(struct device_node *node)
{
	if (!node)
		return NULL;

	ref_count_hold(&node->ref_count);

	return node;
}

static void __node_free(struct ref_count *ref)
{
	struct property *pp, *pp_next;
	struct device_node *node = NULL;
	struct device_node *parent;
	unsigned long flags;
	int ret;

	node = container_of(ref, struct device_node, ref_count);
	if (dt_handle.root == node)
		dt_handle.root = NULL;

	smp_read_lock_irqsave(&node->prop.lock, flags);
	list_for_each_entry_safe(pp, pp_next, &node->prop.list, list) {
		smp_read_unlock_irqrestore(&node->prop.lock, flags);
		ret = dt_delete_property(node, pp->name);
		if (ret)
			pr_err("Failed to delete prop=%s from node=%s (error %d)\n",
				pp->name, node->name, ret);
		smp_read_lock_irqsave(&node->prop.lock, flags);
	}
	smp_read_unlock_irqrestore(&node->prop.lock, flags);

	if (node->parent) {
		parent = node->parent;
		smp_write_lock_irqsave(&parent->child.lock, flags);
		list_del(&node->list);
		smp_write_unlock_irqrestore(&parent->child.lock, flags);
		node->parent = NULL;
		dt_node_loosen(parent);
	}

	kfree(node);
}

/**
 * 释放对系统配置节点的引用
 */
void dt_node_loosen(struct device_node *node)
{
	if (node)
		ref_count_loosen(&node->ref_count, __node_free);
}

/*
 * 判断给定节点是否有子节点
 */
bool is_node_have_child(const struct device_node *node)
{
	struct device_node *np = (struct device_node *)node;
	unsigned long flags;
	bool ret;

	if (!np)
		return FALSE;

	smp_read_lock_irqsave(&np->child.lock, flags);
	ret = list_is_empty(&np->child.list) ? FALSE : TRUE;
	smp_read_unlock_irqrestore(&np->child.lock, flags);

	return ret;
}

/*
 * 获取下一个子节点
 */
struct device_node *dt_get_next_child(const struct device_node *node, struct device_node *cur)
{
	struct device_node *np = (struct device_node *)node;
	struct device_node *next = NULL;
	struct double_list *tmp_list;
	unsigned long flags;

	if (!np)
		return NULL;

	smp_read_lock_irqsave(&np->child.lock, flags);

	/*
	 *如果current属于当前node的子设备节点，则临时链表节点指向current
	 */
	tmp_list = &np->child.list;
	if (cur && cur->parent == np)
		tmp_list = &cur->list;

	if (!list_is_last(tmp_list, &np->child.list))
		next = list_first_container(tmp_list, struct device_node, list);

	if (next)
		dt_node_hold(next);

	smp_read_unlock_irqrestore(&np->child.lock, flags);

	if (cur)
		dt_node_loosen(cur);

	return next;
}

/*
 * 添加一个设备树节点
 */
struct device_node *dt_node_add(struct device_node *parent, const char *name)
{
	struct device_node *node = NULL;
	unsigned long flags;

	if (!name)
		return NULL;

	if (!parent)
		parent = dt_handle.root;

	/*
	 *判断是否存在相同节点
	 */
	if (parent) {
		for_each_child_of_node(node, parent) {
			if (strcmp(node->name, name) == 0) {
				dt_node_loosen(node);
				return NULL;
			}
		}
	}
	/*
	 *初始化设备树节点信息
	 */
	node = kzalloc(sizeof(struct device_node), PAF_ATOMIC);
	if (!node)
		return NULL;
	list_init(&node->list);
	smp_rwlock_init(&node->prop.lock);
	list_init(&node->prop.list);
	smp_rwlock_init(&node->child.lock);
	list_init(&node->child.list);
	ref_count_init(&node->ref_count);
	strncpy(node->name, name, sizeof(node->name));
	node->parent = NULL;
	node->system_data = NULL;
	node->priv = NULL;

	/*
	 *插入到parent链表
	 */
	if (parent) {
		dt_node_hold(parent);
		node->parent = parent;
		smp_write_lock_irqsave(&parent->child.lock, flags);
		list_insert_behind(&node->list, &parent->child.list);
		smp_write_unlock_irqrestore(&parent->child.lock, flags);
	}
	return node;
}

static int _node_dup(struct device_node *dst, struct device_node *src)
{
	struct device_node *child = NULL;
	struct device_node *schild = NULL;
	struct property *pp = NULL;
	int ret;

	for_each_property_of_node(pp, src) {
		ret = dt_set_property(dst, pp->name, pp->value, pp->len);
		if (ret)
			return ret;
	}

	for_each_child_of_node(schild, src) {
		child = dt_node_add(dst, schild->name);
		if (!child) {
			dt_node_loosen(schild);
			return -EINVAL;
		}

		ret = _node_dup(child, schild);
		if (ret) {
			dt_node_loosen(schild);
			return ret;
		}
	}

	return 0;
}

int dt_node_dup(struct device_node *parent, const char *name, struct device_node *src)
{
	struct device_node *node = NULL;

	if (!parent || !name || !src)
		return -EINVAL;

	node = parent;
	while (node && src != node)
		node = node->parent;
	if (src == node)
		return -EINVAL;
	node = NULL;

	node = dt_node_add(parent, name);
	if (!node)
		return -EINVAL;

	return _node_dup(node, src);
}

/*
 * 删除设备树节点
 */
int dt_node_remove(struct device_node *node)
{
	struct device_node *child, *child_next;
	unsigned long flags;
	int ret;

	if (!node)
		return -EINVAL;

	smp_read_lock_irqsave(&node->child.lock, flags);

	list_for_each_entry_safe(child, child_next, &node->child.list, list) {
		smp_read_unlock_irqrestore(&node->child.lock, flags);
		ret = dt_node_remove(child);
		if (ret)
			return ret;
		smp_read_lock_irqsave(&node->child.lock, flags);
	}

	smp_read_unlock_irqrestore(&node->child.lock, flags);

	dt_node_loosen(node);

	return 0;
}

int dt_get_clock_freq(struct device_node *node, u32 *clock_freq)
{
	if (!node || !clock_freq)
		return -EINVAL;

	return dt_read_u32(node, "clock-frequency", clock_freq);
}

/*
 * 判断设备树节点status属性是否为使能状态
 */
bool is_device_available(const struct device_node *node)
{
	const char *stat = NULL;
	u32 statlen = 0;

	if (node == NULL)
		return FALSE;

	stat = dt_get_property(node, "status");
	if (!stat)
		return TRUE;

	statlen = dt_property_size(node, "status");

	if (statlen > 0) {
		if (strcmp(stat, "okay") == 0 || strcmp(stat, "ok") == 0)
			return TRUE;
	}

	return FALSE;
}

bool is_device_big_endian(struct device_node *node)
{
	if (dt_find_property(node, "big-endian"))
		return TRUE;

	if (IS_ENABLED(CONFIG_CPU_BE) && dt_read_bool(node, "native-endian"))
		return TRUE;

	return FALSE;
}

u32 dt_nidtbl_count(void)
{
	return dt_handle.nidtbl_count;
}

struct dt_nidtbl *dt_nidtbl_get(int index)
{
	if ((index < 0) || (dt_handle.nidtbl_count <= index))
		return NULL;

	return &dt_handle.nidtbl[index];
}

static bool __compare_nid_for_matches(const char *subsys, struct dt_nidtbl *nid)
{
	if (!subsys)
		return TRUE;

	return (strcmp(nid->subsys, subsys) == 0) ? TRUE : FALSE;
}

/*
 *从nidtbl创建of_device_id匹配列表
 */
const struct dt_device_id *dt_nidtbl_create_matches(const char *subsys)
{
	const struct dt_device_id *id;
	struct dt_device_id *matches;
	struct dt_nidtbl *nid;
	u32 i, idx, count;

	/*
	 * 计算给定的subsys，匹配的nidtbl数量
	 */
	count = 0;
	for (i = 0; i < dt_handle.nidtbl_count; i++) {
		nid = &dt_handle.nidtbl[i];
		if (__compare_nid_for_matches(subsys, nid))
			count++;
	}

	if (!count)
		return NULL;

	matches = kzalloc((count + 1) * sizeof(struct dt_device_id), PAF_KERNEL);
	if (!matches)
		return NULL;

	/*
	 * 填充matchs table
	 */
	for (i = 0, idx = 0; idx < count && i < dt_handle.nidtbl_count; i++) {
		nid = &dt_handle.nidtbl[i];
		id = &nid->nodeid;
		if (__compare_nid_for_matches(subsys, nid)) {
			memcpy(&matches[idx], id, sizeof(*id));
			idx++;
		}
	}

	return matches;
}

void dt_nidtbl_destroy_matches(const struct dt_device_id *matches)
{
	if (matches)
		kfree((void *)matches);
}

/**
 * 获取设备驱动的match_table.data字段
 */
void *dt_get_match_data(const struct device *dev)
{
	const struct dt_device_id *match;

	if (!dev || !dev->driver)
		return NULL;

	match = dt_match_node(dev->driver->match_table, dev->dt_node);

	return match ? (void*)match->data : NULL;
}

/**
 * 根据传入的设备树blob虚地址初始化设备树
 */
int __init dt_init(void);
int __init dt_init(void)
{
	/*
	 *从设备树文件填充设备树节点
	 */
	return nati_devtree_populate(&dt_handle.root);

#if 0
	/*
	 *计算代码方式定义的设备树节点的数量
	 */
	ntbl_size = nati_nidtbl_size();
	if (!ntbl_size)
		return 0;

	ntbl_vaddr = nati_nidtbl_vaddr();


	ntbl_nr = do_div(ntbl_size, sizeof(*dntbl));
	dt_handle.nidtbl = kzalloc(ntbl_nr * sizeof(*dntbl), PAF_KERNEL);
	if (!dt_handle.nidtbl)
		return -ENOMEM;


	/*
	 *填充设备树节点nidtbl
	 */
	dt_handle.nidtbl_count = 0;
	tmp = ntbl_vaddr;
	while (tmp < (ntbl_vaddr + ntbl_size)) {
		if (*(u32 *)tmp != NIDTBL_MAGIC) {
			tmp += sizeof(u32);
			continue;
		}

		sntbl = (struct dt_nidtbl *)tmp;
		dntbl = &dt_handle.nidtbl[dt_handle.nidtbl_count];

		memcpy(dntbl, sntbl, sizeof(*dntbl));

		dt_handle.nidtbl_count++;
		tmp += sizeof(*sntbl);
	}
#endif

	return 0;
}
